// gorpc/transport/tcp.go

package transport

import (
	"bytes"
	"fmt"
	"gorpc/common"
	"gorpc/protocol"
	"gorpc/server"
	"net"
	"time"
)

type TCPTransport struct {
	addr    string
	maxConn int
	timeout time.Duration
	server  *server.RPCServer
}

func NewTCPTransport(addr string, maxConn int, srv *server.RPCServer) *TCPTransport {
	return &TCPTransport{
		addr:    addr,
		maxConn: maxConn,
		timeout: 30 * time.Second,
		server:  srv,
	}
}

// Listen 服务端监听
func (t *TCPTransport) Listen() (net.Listener, error) {
	listen, err := net.Listen("tcp", t.addr)
	if err != nil {
		return nil, err
	}
	t.addr = listen.Addr().String()
	return listen, nil
}

func (t *TCPTransport) Serve(listener net.Listener) {
	for {
		conn, err := listener.Accept()
		if err != nil {
			// 处理错误（如监听器关闭）
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				continue
			}
			return
		}

		// 启动 goroutine 处理连接
		go t.handleConnection(conn)
	}
}

// 处理单个连接
func (t *TCPTransport) handleConnection(conn net.Conn) {
	defer conn.Close()

	// 读取请求
	msg, err := t.Read(conn)
	if err != nil {
		fmt.Printf("读取失败: %v\n", err)
		return
	}

	// 处理请求（示例：原样返回）
	resp, err := t.server.Dispatch(msg)
	if err != nil {
		fmt.Printf("处理请求失败: %v\n", err)
		return
	}

	if err := t.Write(conn, resp); err != nil {
		fmt.Printf("写入失败: %v\n", err)
		return
	}
}

// Dial 客户端连接
func (t *TCPTransport) Dial() (net.Conn, error) {
	conn, err := net.DialTimeout("tcp", t.addr, t.timeout)
	if err != nil {
		// 使用新的错误构造方式
		return nil, common.NewRPCError(
			common.ErrorCodeConnection,
			"TCP connection failed",
			err,
		)
	}
	return conn, nil
}

// Read 读取完整消息（处理TCP粘包）
func (t *TCPTransport) Read(conn net.Conn) (*protocol.Message, error) {
	message := &protocol.Message{}
	err := message.Decode(conn)
	if err != nil {
		return nil, err
	}
	return message, nil
}

// Write 写入完整消息
func (t *TCPTransport) Write(conn net.Conn, msg *protocol.Message) error {
	buf := bytes.NewBuffer(nil)
	// fmt.Println("in tcp.go Write: ", string(msg.Body))
	if err := msg.Encode(buf); err != nil {
		return err
	}

	_, err := conn.Write(buf.Bytes())
	return err
}
